# -*- coding: utf-8 -*-
# Gestión de características de clase (métodos, atributos, ...)

## vipera, un diseñador de aplicaciones para Python
##     Copyright (C) 2011 Ángel Luis García García
##
##    This program is free software: you can redistribute it and/or modify
##    it under the terms of the GNU General Public License as published by
##    the Free Software Foundation, either version 3 of the License, or
##    (at your option) any later version.
##
##    This program is distributed in the hope that it will be useful,
##    but WITHOUT ANY WARRANTY; without even the implied warranty of
##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##    GNU General Public License for more details.
##
##    You should have received a copy of the GNU General Public License
##    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import wx
import wx.aui
import wx.lib.scrolledpanel as scrolled
from editor2_vipera import panel_codigo_ed
from clases_marcos_vista import panel_const, panel_dest, panel_var_clase
from configuracion_vipera import proy_por_defecto
from i18n_vipera import t

class dialogo(wx.Dialog):
    '''Clase para diálogo de clases de módulos externos'''
    def __init__(self, parent, opcion = 0,idioma = None):
        '''Constructor de clase'''
        # Definimos parámetros.
        if opcion == 0: titulo = t(u'Añadir clase', idioma)
        if opcion == 1: titulo = t(u'Eliminar clase', idioma)
        wx.Dialog.__init__(self, parent, title = titulo,style=wx.DEFAULT_DIALOG_STYLE)
        # Centramos.
        self.Centre()
        # Sizer principal.
        sizer = wx.BoxSizer(wx.VERTICAL)
        # Estamos añadiendo una clase.
        box = wx.BoxSizer(wx.HORIZONTAL)
        label = wx.StaticText(self, -1, t("Clase", idioma))
        box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        self.text_clase = wx.TextCtrl(self, -1, "", size=(80,-1))
        self.text_clase.SetFocus()
        box.Add(self.text_clase, 1, wx.ALIGN_CENTRE|wx.ALL, 5)
        sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        self.text_clase.SetFocus()
        # Línea de separación y botones.
        line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
        sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
        btnsizer = wx.StdDialogButtonSizer()
        btn = wx.Button(self, wx.ID_OK)
        btn.SetDefault()
        btnsizer.AddButton(btn)
        btn = wx.Button(self, wx.ID_CANCEL)
        btnsizer.AddButton(btn)
        btnsizer.Realize()
        sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        self.SetSizer(sizer)
        sizer.Fit(self)

class panel_metodos_p(wx.Panel):
    '''Panel principal de gestión de métodos de clase'''
    def __init__(self, parent, panel_principal, nfilas, idioma = None):
        '''Constructor de clase'''
        wx.Panel.__init__(self, parent)
        # Idioma.
        self.l = idioma
        # Referencia del padre que llama.
        self.panel_principal = panel_principal
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        sbSizer1 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, t(u"Métodos de clase", self.l)), wx.HORIZONTAL )
        self.m_crear = wx.Button( self, wx.ID_ANY, t(u"Crear", self.l), wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
        sbSizer1.Add( self.m_crear, 0, wx.ALIGN_CENTER_VERTICAL, 0 )
        self.m_renombrar = wx.Button( self, wx.ID_ANY, t(u"Renombrar", self.l), wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
        sbSizer1.Add( self.m_renombrar, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        self.m_eliminar = wx.Button( self, wx.ID_ANY, t(u"Eliminar", self.l), wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER )
        sbSizer1.Add( self.m_eliminar, 0, wx.ALIGN_CENTER_VERTICAL, 0 )
        # Botones de expansión
        self.m_bpButton_expandir_panel_der = wx.BitmapButton(self, wx.ID_ANY, wx.Bitmap( u"recursos/images/bp_btn1.png", wx.BITMAP_TYPE_ANY ), wx.DefaultPosition, wx.DefaultSize, wx.BU_AUTODRAW)
        self.m_bpButton_expandir_panel_der.SetToolTipString(t(u"Expandir panel derecho", self.l))
        sbSizer1.Add( self.m_bpButton_expandir_panel_der, 0, wx.ALIGN_CENTER_VERTICAL, 0 )
        self.m_bpButton_expandir_panel_izq = wx.BitmapButton(self, wx.ID_ANY, wx.Bitmap( u"recursos/images/bp_btn2.png", wx.BITMAP_TYPE_ANY ), wx.DefaultPosition, wx.DefaultSize, wx.BU_AUTODRAW )
        self.m_bpButton_expandir_panel_izq.SetToolTipString(t(u"Expandir panel izquierdo",self.l))
        sbSizer1.Add( self.m_bpButton_expandir_panel_izq, 0, wx.ALIGN_CENTER_VERTICAL, 0 )
        # Choice de métodos.
        self.m_metodos = wx.Choice(self, -1)
        # Añadimos al sizer...
        sbSizer1.Add( self.m_metodos, 1, wx.ALIGN_CENTER_VERTICAL, 0)
        bSizer1.Add( sbSizer1, 0, wx.ALL|wx.EXPAND, 2)
        self.m_splitter = wx.SplitterWindow( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SP_3D )
        self.m_splitter.SetMinimumPaneSize( 20 )
        self.m_panel_izq = panel_metodos_param_izq(self.m_splitter, nfilas, idioma = self.l)
        indentacion = 4
        self.m_panel_der = panel_codigo_ed(self.m_splitter, indentacion) 
        self.m_splitter.SplitVertically( self.m_panel_izq, self.m_panel_der, 500)
        self.m_panel_izq.SetupScrolling()
        bSizer1.Add( self.m_splitter, 1, wx.EXPAND, 5 )
        self.SetSizer( bSizer1 )
        self.Layout()
        # Binding.
        self.m_metodos.Bind(wx.EVT_CHOICE, self.OnCambiarMetodoCombo)    
        self.m_crear.Bind(wx.EVT_BUTTON, self.OnCrearMetodo)
        self.m_eliminar.Bind(wx.EVT_BUTTON, self.OnEliminarMetodo)
        self.m_renombrar.Bind(wx.EVT_BUTTON, self.OnRenombrarMetodo)
        self.m_splitter.Bind(wx.EVT_IDLE, self.m_splitterOnIdle)       
        self.m_bpButton_expandir_panel_der.Bind(wx.EVT_BUTTON, self.OnExpandirPanelDer)
        self.m_bpButton_expandir_panel_izq.Bind(wx.EVT_BUTTON, self.OnExpandirPanelIzq)
        self.m_metodos.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMetodos)
        self.m_metodos.Bind(wx.EVT_SET_FOCUS, self.OnSetFocusChoiceMetodos)
        
    def OnSetFocusChoiceMetodos(self, event):
        '''Event handler al cambiar el foco en el choice de métodos.
           Se guardan datos de widgets en modelo de métodos.'''
        self.salvar_info_metodo()
        self.salvar_param_metodo()
        self.salvar_editor_metodo()
        event.Skip()
        
    def OnUpdateMetodos(self, event):
        '''Event handler para activar/desactivar paneles de métodos'''
        metodo = self.m_metodos.GetStringSelection()
        if len(metodo.strip()) != 0:
            self.m_panel_der.Enable(True)
            self.m_panel_izq.Enable(True)
            return
        if self.m_panel_der.IsEnabled() and self.m_panel_izq.IsEnabled():
            # Desactivamos paneles.
            self.m_panel_der.Enable(False)
            self.m_panel_izq.Enable(False)
            # Limpiamos.
            self.limpiar_widget()
        
    def limpiar_widget(self):
        '''Limpiar widgets'''
        self.m_panel_izq.m_info.SetValue('')
        self.m_panel_izq.metodo_oculto.Set3StateValue(wx.CHK_UNCHECKED) # .SetSelection(1)
        for j in self.m_panel_izq.control_texto:
            j[0].SetValue('')
            j[1].SetValue('')
            j[2].SetSelection(0)
        self.m_panel_der.panel.editor.SetText('')

    def __pedir_datos(self, opcion = 0):
        '''Pedir datos mediante un wx.TextEntryDialog.'''
        if opcion == 0: cadena = t(u'Nombre del nuevo método: ', self.l)
        if opcion == 1: cadena = t(u'Renombrar método: ', self.l)
        dialogo = wx.TextEntryDialog(self, cadena, t(u'Método', self.l))
        dialogo.Show()
        if dialogo.ShowModal() == wx.ID_OK:
            ret = dialogo.GetValue()
        else:
            # Botón cancelar. Nada que devolver.
            ret = None
        # Limpiamos memoria y nos vamos.
        dialogo.Destroy()
        return ret   

    def OnExpandirPanelIzq(self, event):
        '''Expandir panel izquierdo por completo'''
        self.m_splitter.SetSashPosition(10000)

    def OnExpandirPanelDer(self, event):
        '''Expandir panel derecho por completo'''
        self.m_splitter.SetSashPosition(20)

    def m_splitterOnIdle( self, event ):
        '''Posición inicial del splitter'''
        self.m_splitter.SetSashPosition(500)
        self.m_splitter.Unbind( wx.EVT_IDLE )

    def OnCambiarMetodoCombo(self, event):
        '''Método para cambiar métodos en el configurador de características'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Limpiamos todo.
        self.limpiar_widget()
        # Obtenemos el método actual.
        metodo = self.m_metodos.GetStringSelection()
        if len(metodo) == 0: return
        # Recorremos la estructura para el traspaso de datos.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                for j in i[0].metodos:
                    if j[0] == metodo:
                        # Información del método.
                        info_metodo = j[1]
                        # Parámetros del método.
                        param_metodo = j[2]
                        # Código Python del método.
                        codigo_python = j[3]
                        # ¿Método oculto?
                        metodo_oculto = j[4]
                        # Incluimos información en el método.
                        self.m_panel_izq.m_info.SetValue(info_metodo)
                        # Incluimos código Python en el método.
                        self.m_panel_der.panel.editor.SetText(codigo_python)
                        # Incluimos si el método es oculto ó no.
                        self.m_panel_izq.metodo_oculto.Set3StateValue(metodo_oculto)
                        # Incluimos parámetros del método.
                        indice = 0
                        for h in param_metodo:
                            k = self.m_panel_izq.control_texto[indice]
                            k[0].SetValue(h[0])
                            k[1].SetValue(h[1])
                            k[2].SetStringSelection(h[2])
                            indice += 1   
                        break
                break    

    def OnCrearMetodo(self, event):
        '''Event handler para crear método'''
        # Nombre del método.
        nombre_metodo = self.__pedir_datos()
        if nombre_metodo is None: return
        try:
            if len(str(nombre_metodo).strip()) == 0: return
        except: return
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()

        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Buscamos entre las clases
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Comprobamos que no exista el método.
                for u in i[0].metodos:
                    if u[0] == nombre_metodo.strip():
                        wx.MessageBox(t(u"¡El método ya existe!", self.l) ,t(u"Atención", self.l),wx.OK)
                        return
                # Creamos la estructura de métodos.
                # 0 - > Nombre método, 1 - > Información
                # 2 - > Lista Parámetros, 3 - > Código Python.
                # 4 - > Método oculto.
                i[0].metodos.append([nombre_metodo.strip(), '', list(), '', False])
                # Y nos vamos.
                break
        # Incluimos el nombre dentro del combo.
        self.m_metodos.AppendItems([nombre_metodo.strip()])

        # #######################################################
        # Y pintamos los métodos en la caja dividedshape del OGL.
        # #######################################################

        # Obtenemos todos los nombres de los métodos de clase.
        nombre_metodos = self.m_metodos.GetItems()
        # Añadimos un nuevo nombre en el dividedshape del OGL.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Pintamos los métodos en la tercera región del dividedshape.
                self.panel_principal.panel_ogl.ogl_nombre_metodos(i[1],nombre_metodos)
                break

    def OnEliminarMetodo(self, event):
        '''Event handler para eliminación del método'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Nombre del método.
        nombre_metodo = self.m_metodos.GetStringSelection().strip()
        if len(nombre_metodo) == 0:
            wx.MessageBox(t(u"Seleccione antes un método", self.l), t(u"Atención", self.l),wx.OK)
            return
        # Preguntamos si se quiere salir.
        i = wx.MessageBox(t(u"¿Eliminar método?", self.l), t(u"Atención", self.l), wx.YES_NO)
        if i != wx.YES: return
        # Flag de salida.
        salir = False
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                for j in i[0].metodos:
                    if j[0] == nombre_metodo:
                        # Eliminamos elemento de la lista.
                        i[0].metodos.remove(j)
                        salir = True
                        break
                if salir: break
        # Y lo eliminamos del combo.
        aux = self.m_metodos.GetItems()
        item_a_eliminar = self.m_metodos.GetStringSelection()
        aux.remove(item_a_eliminar)
        self.m_metodos.SetItems(aux)
        # self.m_metodos.SetValue("")
        # Y limpiamos todo.
        self.limpiar_widget()

        # #####################################################
        # Pintamos los métodos en la caja dividedshape del OGL.
        # #####################################################

        # Obtenemos todos los nombres de los métodos de clase.
        nombre_metodos = self.m_metodos.GetItems()
        # Añadimos un nuevo nombre en el dividedshape del OGL.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Pintamos los métodos en la tercera región del dividedshape.
                self.panel_principal.panel_ogl.ogl_nombre_metodos(i[1],nombre_metodos)
                break

    def OnRenombrarMetodo(self, event):
        '''Event handler para renombrar método'''
        id_combo = self.m_metodos.GetSelection()
        if id_combo == wx.NOT_FOUND:
            wx.MessageBox(t(u"Seleccione antes un método", self.l),t(u"Atención", self.l),wx.OK)
            return
        old_name = self.m_metodos.GetStringSelection()
        # Pedimos nuevo nombre de método.
        new_name = self.__pedir_datos(1)
        if new_name is None: return
        try:
            if len(str(new_name).strip()) == 0: return
        except: return
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Flag de salida.
        salir = False
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                for u in i[0].metodos:
                    if u[0] == new_name.strip():
                        wx.MessageBox(t(u"¡El método ya existe!", self.l),t(u"Atención", self.l),wx.OK)
                        return
                for j in i[0].metodos:
                    if j[0] == old_name:
                        j[0] = new_name
                        salir = True
                        break
                if salir: break
        # Cambiamos el nombre del método en el combo.
        self.m_metodos.SetString(id_combo, new_name)
        # self.m_metodos.SetValue(new_name)
        self.m_metodos.SetSelection(id_combo)

        # #####################################################
        # Pintamos los métodos en la caja dividedshape del OGL.
        # #####################################################

        # Obtenemos todos los nombres de los métodos de clase.
        nombre_metodos = self.m_metodos.GetItems()
        # Añadimos un nuevo nombre en el dividedshape del OGL.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Pintamos los métodos en la tercera región del dividedshape.
                self.panel_principal.panel_ogl.ogl_nombre_metodos(i[1],nombre_metodos)
                break

    def salvar_info_metodo(self):
        '''Guardamos el comentario y la ocultación de método'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Identificamos el método.
                metodo = self.m_metodos.GetStringSelection()
                if len(metodo) == 0: return
                for j in i[0].metodos:
                    if j[0] == metodo:
                        j[1] = self.m_panel_izq.m_info.GetValue()
                        j[4] = self.m_panel_izq.metodo_oculto.Get3StateValue() # GetStringSelection()
                        break
                break	    

    def salvar_param_metodo(self):
        '''Guardamos los parámetros de método'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Nombre del método.
        metodo = self.m_metodos.GetStringSelection()
        if len(metodo) == 0: return
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Identificamos el método.
                for h in i[0].metodos:
                    if h[0] == metodo:
                        h[2] = list()
                        # Recorremos todo el widget, incluyendo solo los datos válidos.
                        for j in self.m_panel_izq.control_texto:
                            if j[0].GetValue() is None or len(j[0].GetValue()) == 0: continue
                            if j[1].GetValue() is None or len(j[1].GetValue()) == 0: j[1].SetValue('')
                            h[2].append([j[0].GetValue(),j[1].GetValue(),
                                         j[2].GetStringSelection()])
                        break
                break

    def salvar_editor_metodo(self):
        '''Guardamos el código extra de método'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Identificamos el método.
                metodo = self.m_metodos.GetStringSelection()
                if len(metodo) == 0: return
                for j in i[0].metodos:
                    if j[0] == metodo:
                        j[3] = self.m_panel_der.panel.editor.GetText()
                        break
                break

    #def salvar_clase(self):
        ## Definición de clase.
        #self.salvar_def_clase()
        ## Parámetros de instanciación de clase.
        #self.salvar_param_inst_clase()
        ## Atributos de clase.
        #self.salvar_atrib_clase()
        ## Métodos de clase.
        #self.salvar_info_metodo()
        #self.salvar_param_metodo()
        #self.salvar_editor_metodo()
        ## Propiedades de clase.
        #self.salvar_prop_clase()
        ## Información de clase.
        #self.salvar_info_clase()
        ## Constantes de clase.
        #self.salvar_cte_clase()
        ## Constructor de clase.
        #self.salvar_constructor_clase()
        ## Destructor de clase.
        #self.salvar_destructor_clase()

class panel_nombre_clase(scrolled.ScrolledPanel):
    '''Panel de nombre de clase'''
    def __init__(self, parent, panel_principal, idioma = None):
        '''Constructor de clase'''
        scrolled.ScrolledPanel.__init__ ( self, parent, -1)
        # Panel principal.
        self.panel_principal = panel_principal
        # Idioma.
        self.l = idioma
        # Sizer principal.
        bSizer = wx.BoxSizer( wx.VERTICAL )
        # Texto estático.
        self.m_nombre_clase = wx.StaticText( self, wx.ID_ANY, t(u"NOMBRE DE LA CLASE", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        self.m_nombre_clase.Wrap( -1 )
        self.m_nombre_clase.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
        # Lo añadimos al sizer.
        bSizer.Add( self.m_nombre_clase, 0, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 20 )
        # Caja de texto del nombre de la clase.
        self.m_textCtrl_nc = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_READONLY)
        self.m_textCtrl_nc.SetForegroundColour(wx.Colour(255, 0, 0))
        bSizer.Add( self.m_textCtrl_nc, 0, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 20 )
        # [19-06-2011] Se incluyen las clases de las que se hereda.
        # Texto estático.
        self.m_hereda_de = wx.StaticText( self, wx.ID_ANY, t(u"HEREDA DE (clases en módulo actual)", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        self.m_hereda_de.Wrap( -1 )
        self.m_hereda_de.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
        # Lo añadimos al sizer.
        bSizer.Add( self.m_hereda_de, 0, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 20 )
        # Caja de texto del nombre de la clase.
        self.m_textCtrl_hereda = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_READONLY )
        self.m_textCtrl_hereda.SetForegroundColour( wx.Colour( 247, 240, 240 ) )
        self.m_textCtrl_hereda.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_GRAYTEXT ) )
        # Se añade al sizer.
        bSizer.Add( self.m_textCtrl_hereda, 0, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 20)
        # [27-07-2011] Se incluyen las clases externas al módulo de las que se hereda.
        # Texto estático.
        self.m_hereda_de_ext = wx.StaticText( self, wx.ID_ANY, t(u"HEREDA DE (clases en módulos externos)", self.l))
        self.m_hereda_de_ext.Wrap( -1 )
        self.m_hereda_de_ext.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 65, 90, 92, False, wx.EmptyString ) )
        # Lo añadimos al sizer.
        bSizer.Add(self.m_hereda_de_ext, 0, wx.ALL|wx.EXPAND, 20)
        # Creamos botones de creación y eliminación de clases de otros módulos.
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.add_clase = wx.Button(self, -1, t(u'Crear clase', self.l))
        self.eliminar_todo = wx.Button(self, -1, t(u'Borrar todo', self.l))
        sizer.Add(self.add_clase, 0, wx.ALL|wx.EXPAND, 0)
        sizer.Add(self.eliminar_todo, 0, wx.ALL|wx.EXPAND, 0)
        # Lo añadimos al sizer.
        bSizer.Add(sizer, 0, wx.ALL|wx.EXPAND, 20 )
        # Caja de texto del nombre de la clase.
        self.m_textCtrl_hereda_ext = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_READONLY )
        self.m_textCtrl_hereda_ext.SetForegroundColour( wx.Colour( 255, 255, 255 ) )
        self.m_textCtrl_hereda_ext.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_HIGHLIGHT ) )
        # Se añade al sizer.
        bSizer.Add( self.m_textCtrl_hereda_ext, 0, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 20)
        # Lo añadimos al sizer.
        self.SetSizer( bSizer )
        self.Layout()
        # Incluimos bindings de botones.
        self.eliminar_todo.Bind(wx.EVT_BUTTON, self.OnEliminar)
        self.add_clase.Bind(wx.EVT_BUTTON, self.OnAddClase)
        self.SetupScrolling()

    def limpiar_widget(self):
        '''Limpia widgets'''
        self.m_textCtrl_hereda.SetValue('')
        self.m_textCtrl_hereda_ext.SetValue('')
        self.m_textCtrl_nc.SetValue('')
        
    def salvar_def_clase(self):
        '''Guardamos las clases externas'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                i[0].clases_externas = self.m_textCtrl_hereda_ext.GetValue()
                break
        
    # ######################
    # Manejadores de eventos
    # ######################

    def OnEliminar(self, event):
        '''Event handler de eliminación de clase externa'''
        self.m_textCtrl_hereda_ext.SetValue('')

    def OnAddClase(self, event):
        '''Event handler de creación de clase externa'''
        a = dialogo(self, idioma = self.l)
        a.Show()
        if a.ShowModal() == wx.ID_OK:
            t = a.text_clase.GetValue().strip()    
            if len(t) == 0: return
            clases = self.m_textCtrl_hereda_ext.GetValue().split(',')
            clases.append(t)
            ret = ''
            for i in clases: 
                if len(ret.strip()) == 0:
                    ret += i
                else:
                    ret += '%s%s' % (', ',i)
            # Incluimos las clases en el control de texto.
            self.m_textCtrl_hereda_ext.SetValue(ret)
            # Y le damos el foco para que cuando lo pierda
            # podamos grabar los datos en la estructura.
            self.m_textCtrl_hereda_ext.SetFocus()

class panel_metodos_param_izq(scrolled.ScrolledPanel):
    '''Panel de parámetros de métodos de clase'''
    def __init__(self, parent, nfilas = 1, idioma = None):
        '''Constructor de clase'''
        scrolled.ScrolledPanel.__init__(self, parent, style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        # Idioma.
        self.l = idioma
        # Lista de TextCtrl.
        self.control_texto = []
        # Definimos sizer principal.
        sizer_p = wx.BoxSizer(wx.VERTICAL)
        # [25-05-2011] FlexGridSizer de comentarios.
        fgs_p = wx.FlexGridSizer(2,1,5,5)
        fgs_p.AddGrowableCol(0)
        fgs_p.AddGrowableRow(0)
        fgs_p.AddGrowableRow(1)
        fgs_p.SetFlexibleDirection(wx.BOTH)
        fgs_p.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
        # Cajas de texto...
        self.m_info_t = wx.StaticText( self, wx.ID_ANY,t(u"Información de método", self.l), wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_info_t.Wrap( -1 )
        self.m_info = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE )
        fgs_p.Add( self.m_info_t, 0, wx.ALL|wx.EXPAND, 5 )
        fgs_p.Add( self.m_info, 0, wx.ALL|wx.EXPAND, 5 )
        # [28-07-2011] Incluimos elección de método oculto ó público.
        # Textos.
        # m_texto_o = wx.StaticText( self, wx.ID_ANY, t(u"OCULTO", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        # m_texto_o.Wrap(-1)
        # Choice de elección
        # eleccion_choice = [ u"Si", u"No" ]
        # self.metodo_oculto = wx.Choice(self, -1, wx.DefaultPosition, wx.DefaultSize, eleccion_choice, 0)
        self.metodo_oculto = wx.CheckBox(self, -1, t(u"OCULTO", self.l))
        self.metodo_oculto.Set3StateValue(wx.CHK_UNCHECKED) # SetSelection(1)
        # Sizer horizontal.
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        # sizer.Add(m_texto_o, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        sizer.Add(self.metodo_oculto, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        # E incluimos este sizer horizontal al flexgridsizer principal.
        fgs_p.Add(sizer, 0, wx.ALL|wx.EXPAND, 5 )
        # FlexGridSizer de cajas de texto.
        fgs = wx.FlexGridSizer(200,3,5,5)
        fgs.AddGrowableCol(0)
        fgs.AddGrowableCol(1)
        fgs.AddGrowableCol(2)
        for i in range(0,199):
            fgs.AddGrowableRow(i)
        fgs.SetFlexibleDirection(wx.BOTH)
        fgs.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
        # Textos.
        m_texto_p = wx.StaticText( self, wx.ID_ANY, t(u"PARÁMETROS", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_p.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_p, 0, wx.ALL|wx.EXPAND, 5 )
        # Textos.
        m_texto_v = wx.StaticText( self, wx.ID_ANY, t(u"VALOR POR DEFECTO", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_v.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_v, 0, wx.ALL|wx.EXPAND, 5 )
        # Textos.
        m_texto_t = wx.StaticText( self, wx.ID_ANY, t(u"VALIDAR TIPO DE DATO COMO", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_t.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_t, 0, wx.ALL|wx.EXPAND, 5 )
        # Recorremos y creamos cajas dinámicamente.
        for i in range(0,nfilas):
            # Nombre del parámetro.
            p = wx.TextCtrl(self, -1)
            # Valor por defecto.
            v = wx.TextCtrl(self, -1)
            # Tipo de valor (assert).
            m_choice_tipo_datoChoices = proy_por_defecto['tipo_dato_python']
            tt = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_choice_tipo_datoChoices, 0 )
            tt.SetSelection( 0 )
            # Incluimos los controles en lista.
            self.control_texto.append((p,v,tt))
            # Añadimos controles al flexgridsizer.
            fgs.Add(p, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(v, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(tt, 0, wx.ALL|wx.EXPAND, 5 )
            # fgs.Add(o, 0, wx.ALL|wx.EXPAND, 5 )	    
        # [25-05-2011] Añadimos el flexgridsizer de comentarios al sizer principal.
        sizer_p.Add(fgs_p, 0, wx.ALL|wx.EXPAND, 5)
        # Añadimos el flexgridsizer al sizer principal.
        sizer_p.Add(fgs, 0, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(sizer_p)
        self.Layout()

class panel_coment_clase(scrolled.ScrolledPanel):
    '''Panel de comentarios de clase'''
    def __init__(self, parent, panel_principal, nfilas = 1, idioma = None):
        '''Constructor de clase'''
        scrolled.ScrolledPanel.__init__(self, parent, style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        # Panel principal.
        self.panel_principal = panel_principal
        # Definimos sizer principal.
        sizer_p = wx.BoxSizer(wx.VERTICAL)
        # Caja de comentario.
        self.m_textCtrl_coment = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString,
                                              wx.DefaultPosition, wx.DefaultSize,
                                              wx.HSCROLL|wx.TE_MULTILINE )
        # Lo incluimos en el sizer.
        sizer_p.Add(self.m_textCtrl_coment, 1, wx.ALL|wx.EXPAND, 5 )
        # Añadimos el flexgridsizer al sizer principal.
        self.SetSizer(sizer_p)
        self.Layout()

    def limpiar_widget(self):
        '''Limpiar widgets'''
        self.m_textCtrl_coment.SetValue('')
        
    def salvar_info_clase(self):
        '''Guardamos el comentario de clase'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                i[0].comentario = self.panel_principal.panel_info_clases.m_textCtrl_coment.GetValue()
                break
        
class panel_param_inst(scrolled.ScrolledPanel):
    '''Panel de parámetros de instanciación de clase'''
    def __init__(self, parent, panel_principal, nfilas = 1, idioma = None):
        '''Constructor de clase'''
        scrolled.ScrolledPanel.__init__(self, parent, style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        # Panel principal.
        self.panel_principal = panel_principal
        # Idioma.
        self.l = idioma
        # Lista de TextCtrl.
        self.control_texto = []        
        # Definimos sizer principal.
        sizer_p = wx.BoxSizer(wx.VERTICAL)
        # FlexGridSizer de cajas de texto.
        fgs = wx.FlexGridSizer(200,2,5,5)
        fgs.AddGrowableCol(0)
        fgs.AddGrowableCol(1)
        for i in range(0,199):
            fgs.AddGrowableRow(i)
        fgs.SetFlexibleDirection(wx.BOTH)
        fgs.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
        # Textos.
        m_texto_p = wx.StaticText( self, wx.ID_ANY, t(u"PARÁMETROS", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_p.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_p, 0, wx.ALL|wx.EXPAND, 5 )
        # Textos.
        m_texto_v = wx.StaticText( self, wx.ID_ANY, t(u"VALORES DE INICIALIZACIÓN", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_v.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_v, 0, wx.ALL|wx.EXPAND, 5 )
        for i in range(0,nfilas):
            # Nombre del parámetro.
            p = wx.TextCtrl(self, -1)
            # Valor por defecto.
            v = wx.TextCtrl(self, -1)
            # Incluimos los controles en lista.
            self.control_texto.append((p,v))
            # Añadimos controles al flexgridsizer.
            fgs.Add(p, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(v, 0, wx.ALL|wx.EXPAND, 5 )
        # Añadimos el flexgridsizer al sizer principal.
        sizer_p.Add(fgs, 0, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(sizer_p)
        self.Layout()
        # ¡Setup!
        self.SetupScrolling()

    def limpiar_widget(self):
        '''Limpiar widgets'''
        for i in self.control_texto:
            i[0].SetValue('')
            i[1].SetValue('')

    def salvar_param_inst_clase(self):
        '''Guardamos los parámetros de instanciación'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                i[0].parametros = []
                # Recorremos todo el widget, incluyendo solo los datos válidos.
                for j in self.control_texto:
                    if j[0].GetValue() is None or len(j[0].GetValue()) == 0: continue
                    if j[1].GetValue() is None or len(j[1].GetValue()) == 0: j[1].SetValue('')
                    i[0].parametros.append([j[0].GetValue(),j[1].GetValue()])
                break
            
class panel_atrib_clase(scrolled.ScrolledPanel):
    '''Panel de atributos de clase'''
    def __init__(self, parent, panel_principal, nfilas = 1, idioma = None):
        '''Constructor de clase'''
        scrolled.ScrolledPanel.__init__(self, parent, style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        # Panel principal.
        self.panel_principal = panel_principal
        # Idioma.
        self.l = idioma
        # Lista de TextCtrl.
        self.control_texto = []        
        # Definimos sizer principal.
        sizer_p = wx.BoxSizer(wx.VERTICAL)
        # FlexGridSizer de cajas de texto.
        # [19-06-2011] Se incluye atributo oculto.
        fgs = wx.FlexGridSizer(200,3,5,5)
        fgs.AddGrowableCol(0)
        fgs.AddGrowableCol(1)
        for i in range(0,199):
            fgs.AddGrowableRow(i)
        fgs.SetFlexibleDirection(wx.BOTH)
        fgs.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
        # Textos.
        m_texto_p = wx.StaticText( self, wx.ID_ANY, t(u"ATRIBUTOS", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_p.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_p, 0, wx.ALL|wx.EXPAND, 5 )
        # Textos.
        m_texto_v = wx.StaticText( self, wx.ID_ANY, t(u"VALOR POR DEFECTO", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_v.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_v, 0, wx.ALL|wx.EXPAND, 5 )
        # Textos.
        m_texto_o = wx.StaticText( self, wx.ID_ANY, t(u"OCULTO", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_o.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_o, 0, wx.ALL|wx.EXPAND, 5 )
        for i in range(0,nfilas):
            # Nombre del atributo.
            p = wx.TextCtrl(self, -1)
            v = wx.TextCtrl(self, -1)
            # [19-06-2011] Atributo oculto.
            # eleccion_choice = [ u"Si", u"No" ]
            # o = wx.Choice(self, -1, wx.DefaultPosition, wx.DefaultSize, eleccion_choice, 0)
            # o.SetSelection(0)
            o = wx.CheckBox(self, -1) # t(u"OCULTO", self.l))
            o.Set3StateValue(wx.CHK_CHECKED)
            # Incluimos los controles en lista.
            self.control_texto.append((p,v,o))
            # Añadimos controles al flexgridsizer.
            fgs.Add(p, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(v, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(o, 0, wx.ALL|wx.ALIGN_CENTER, 5 )
        # Añadimos el flexgridsizer al sizer principal.
        sizer_p.Add(fgs, 0, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(sizer_p)
        self.Layout()
        # ¡Setup!
        self.SetupScrolling()

    def limpiar_widget(self):
        '''Limpiar widgets'''
        for i in self.control_texto:
            i[0].SetValue('')
            i[1].SetValue('')
            i[2].Set3StateValue(wx.CHK_CHECKED) # i[2].SetSelection(0)
        
    def salvar_atrib_clase(self):
        '''Guardamos los atributos de la clase'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        if len(clases) == 0: return
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        ds = None
        for i in clases: 
            if i[0].nombre == nombre_clase:
                ds = i[1]
                i[0].atributos = []
                # Recorremos todo el widget, incluyendo solo los datos válidos.
                for j in self.control_texto:
                    if j[0].GetValue() is None or len(j[0].GetValue()) == 0: continue
                    if j[1].GetValue() is None or len(j[1].GetValue()) == 0: j[1].SetValue('')
                    i[0].atributos.append([j[0].GetValue(),j[1].GetValue(),
                                           j[2].Get3StateValue()])
                break
        # Incluimos los atributos y propiedades en la caja del dividedshape.
        if ds is not None:
            self.panel_principal.panel_ogl.ogl_nombre_atributos(ds, i[0].atributos, i[0].propiedades)
        # [23-06-2011] Buscamos en los valores predeterminados de los atributos nombres de clases
        # para tratar las relaciones de dependencia ó instanciación, esto es, la instanciación
        # de clases en atributos.
        # Recogemos todos los nombres de clases del módulo.
        lista_clases = list()
        for i in clases: lista_clases.append(i[0].nombre.strip())
        # Recorremos los atributos.
        clase_hijo = ds
        for j in self.control_texto:
            # Nombre de clase que está en el valor predeterminado del atributo.
            nombre_clase_padre = j[1].GetValue().split("(")[0].strip()
            # Una clase no se puede autoreferenciar.
            if nombre_clase == nombre_clase_padre: continue
            # Referencia del dividedshape de la clase padre.
            clase_padre = self.panel_principal.panel_ogl.modelo.get_divided_shape(nombre_clase_padre)
            # Existe la relación de dependencia y el atributo.    
            if len(j[0].GetValue()) != 0 and nombre_clase_padre in lista_clases: 
                # Damos de alta la relación de dependencia en la estructura (si no existe).
                if self.panel_principal.panel_ogl.relacion_dep.crear_relacion(clase_padre, clase_hijo):
                    # Pintamos la relación en el OGL.
                    if not None in [clase_padre, clase_hijo]:
                        self.panel_principal.panel_ogl.dibujar_relacion_dependencia(clase_padre, clase_hijo)
        # Ahora recorremos la estructura, para buscar posibles modificaciones.
        relaciones_dep = self.panel_principal.panel_ogl.relacion_dep.relaciones()
        # Nombre de la clase hijo.
        nombre_hijo = nombre_clase
        for j in relaciones_dep:
            if j[1] == clase_hijo:
                # Obtenemos la referencia del padre.
                clase_padre = j[0]
                # El nombre del padre.
                for k in clases: 
                    if k[1] == clase_padre:
                        nombre_clase_padre = k[0].nombre
                        break
                eliminar_relacion = True
                for l in self.control_texto:
                    # Caso para la no eliminación.
                    if nombre_clase_padre == l[1].GetValue().split("(")[0].strip() and \
                       len(l[0].GetValue().strip()) != 0:
                        eliminar_relacion = False
                        break
                # ¿Eliminar relación?
                if eliminar_relacion:
                    # Eliminamos de la estructura.
                    self.panel_principal.panel_ogl.relacion_dep.eliminar_relacion(clase_padre,clase_hijo)
                    # Y eliminamos del OGL.
                    self.panel_principal.panel_ogl.eliminar_dibujo_relacion_dependencia(clase_padre, clase_hijo)
            
class panel_prop_clase(scrolled.ScrolledPanel):
    '''Panel de propiedades de clase'''
    def __init__(self, parent, panel_principal, nfilas = 1, idioma = None):
        '''Constructor de clase'''
        scrolled.ScrolledPanel.__init__(self, parent, style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
        # Panel principal.
        self.panel_principal = panel_principal
        # Idioma.
        self.l = idioma
        # Lista de TextCtrl.
        self.control_texto = []        
        # Definimos sizer principal.
        sizer_p = wx.BoxSizer(wx.VERTICAL)
        # FlexGridSizer de cajas de texto.
        fgs = wx.FlexGridSizer(200,3,5,5)
        fgs.AddGrowableCol(0)
        fgs.AddGrowableCol(1)
        fgs.AddGrowableCol(2)
        for i in range(0,199):
            fgs.AddGrowableRow(i)
        fgs.SetFlexibleDirection(wx.BOTH)
        fgs.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
        # Textos.
        m_texto_p = wx.StaticText( self, wx.ID_ANY, t(u"PROPIEDADES", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_p.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_p, 0, wx.ALL|wx.EXPAND, 5 )
        # Textos.
        m_texto_v = wx.StaticText( self, wx.ID_ANY, t(u"VALOR POR DEFECTO", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_v.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_v, 0, wx.ALL|wx.EXPAND, 5 )
        # Información.
        m_texto_i = wx.StaticText( self, wx.ID_ANY, t(u"INFORMACIÓN", self.l), wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
        m_texto_i.Wrap(-1)
        # Añadimos texto al flexgridsizer.
        fgs.Add(m_texto_i, 0, wx.ALL|wx.EXPAND, 5 )        
        for i in range(0,nfilas):
            # Nombre del parámetro.
            p = wx.TextCtrl(self, -1)
            # Valor por defecto.
            v = wx.TextCtrl(self, -1)
            # Información.
            i = wx.TextCtrl(self, -1)
            # Incluimos los controles en lista.
            self.control_texto.append((p,v,i))
            # Añadimos controles al flexgridsizer.
            fgs.Add(p, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(v, 0, wx.ALL|wx.EXPAND, 5 )
            fgs.Add(i, 0, wx.ALL|wx.EXPAND, 5 )            
        # Añadimos el flexgridsizer al sizer principal.
        sizer_p.Add(fgs, 0, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(sizer_p)
        self.Layout()
        # ¡Setup!
        self.SetupScrolling()

    def limpiar_widget(self):
        '''Limpiar widgets'''
        for i in self.control_texto:
            i[0].SetValue('')
            i[1].SetValue('')
            i[2].SetValue('')

    def salvar_prop_clase(self):
        '''Guardamos las propiedades de la clase'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        ds = None
        for i in clases: 
            if i[0].nombre == nombre_clase:
                ds = i[1]
                i[0].propiedades = []
                # Recorremos todo el widget, incluyendo solo los datos válidos.
                for j in self.control_texto:
                    if j[0].GetValue() is None or len(j[0].GetValue()) == 0: continue
                    if j[1].GetValue() is None or len(j[1].GetValue()) == 0: j[1].SetValue('')
                    i[0].propiedades.append([j[0].GetValue(),j[1].GetValue(),j[2].GetValue()])
                break
        # Incluimos los atributos y propiedades en la caja del dividedshape.
        if ds is not None:
            self.panel_principal.panel_ogl.ogl_nombre_atributos(ds, i[0].atributos, i[0].propiedades)
            
class panel_const_p(panel_const):
    '''Panel constructor de clase'''
    def __init__(self, parent, panel_principal, idioma = None):
        '''Constructor de clase'''
        panel_const.__init__(self, parent)
        # Panel principal.
        self.panel_principal = panel_principal
        # Idioma.
        self.l = idioma
        # Cambiamos idioma en widgets de wxFB.
        self.m_checkBox_ini.SetLabel(t(u'Código constructor inicial', self.l))
        self.m_checkBox_fin.SetLabel(t(u'Código constructor final', self.l))
        indentacion = 4
        self.editor_ini = panel_codigo_ed(self.m_panel_ini, indentacion)
        self.editor_fin = panel_codigo_ed(self.m_panel_fin, indentacion)        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.editor_ini, 1, wx.ALL|wx.EXPAND, 5)
        self.m_panel_ini.SetSizer(sizer)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.editor_fin, 1, wx.ALL|wx.EXPAND, 5)
        self.m_panel_fin.SetSizer(sizer)

    def limpiar_widget(self):
        '''Limpiar widgets'''
        self.editor_ini.panel.editor.SetText('')
        self.editor_fin.panel.editor.SetText('')
        self.m_checkBox_fin.Set3StateValue(wx.CHK_UNCHECKED)
        self.m_checkBox_ini.Set3StateValue(wx.CHK_UNCHECKED)

    def salvar_constructor_clase(self):
        '''Guardamos código extra del constructor'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Recogemos datos del constructor.
                ejecutar_codigo_ini = self.m_checkBox_ini.GetValue()
                codigo_ini = self.editor_ini.panel.editor.GetText()
                ejecutar_codigo_fin = self.m_checkBox_fin.GetValue()
                codigo_fin = self.editor_fin.panel.editor.GetText()
                # Guardamos datos en estructura interna.
                i[0].codigo_constructor_ini = [codigo_ini, ejecutar_codigo_ini]
                i[0].codigo_constructor_fin = [codigo_fin, ejecutar_codigo_fin]
                break
            
class panel_dest_p(panel_dest):
    '''Panel destructor de clase'''
    def __init__(self, parent, panel_principal, idioma = None):
        '''Constructor de clase'''
        panel_dest.__init__(self, parent)
        # Panel principal.
        self.panel_principal = panel_principal
        # idioma.
        self.l = idioma
        # Cambiamos idioma en widgets de wxFB.
        self.m_checkBox_ini.SetLabel(t(u'Código destructor', self.l))
        indentacion = 4
        self.editor = panel_codigo_ed(self.m_panel, indentacion)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.editor, 1, wx.ALL|wx.EXPAND, 5)
        self.m_panel.SetSizer(sizer)

    def limpiar_widget(self):
        '''Limpiar widgets'''
        self.editor.panel.editor.SetText('')
        self.m_checkBox_ini.Set3StateValue(wx.CHK_UNCHECKED)

    def salvar_destructor_clase(self):
        '''Guardamos código del destructor'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Recogemos datos del constructor.
                ejecutar_codigo = self.m_checkBox_ini.GetValue()
                codigo = self.editor.panel.editor.GetText()
                # Guardamos datos en estructura interna.
                i[0].codigo_destructor = [codigo, ejecutar_codigo]
                break
    
class dialogo_cte_clase(wx.Dialog):
    '''Clase para diálogo de menús'''
    def __init__(self, parent, idioma = None):
        '''Constructor de clase'''
        # Idioma.
        self.l = idioma
        # Definimos parámetros.
        titulo = t(u'Constantes de clase', self.l)
        wx.Dialog.__init__(self, parent, title = titulo,style=wx.DEFAULT_DIALOG_STYLE)
        # Sizer principal.
        sizer = wx.BoxSizer(wx.VERTICAL)
        # Primer elemento.
        box = wx.BoxSizer(wx.HORIZONTAL)
        label = wx.StaticText(self, -1, t("Clave/Constante", self.l))
        box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        self.text_clave = wx.TextCtrl(self, -1, "", size=(80,-1))
        self.text_clave.SetFocus()
        box.Add(self.text_clave, 1, wx.ALIGN_CENTRE|wx.ALL, 5)
        sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        # Segundo elemento.
        box = wx.BoxSizer(wx.HORIZONTAL)
        label = wx.StaticText(self, -1, t("Valor", self.l))
        box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        self.text_valor = wx.TextCtrl(self, -1, "", size=(80,-1))
        box.Add(self.text_valor, 1, wx.ALIGN_CENTRE|wx.ALL, 5)
        sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        # Línea de separación y botones.
        line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
        sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
        btnsizer = wx.StdDialogButtonSizer()
        btn = wx.Button(self, wx.ID_OK)
        btn.SetDefault()
        btnsizer.AddButton(btn)
        btn = wx.Button(self, wx.ID_CANCEL)
        btnsizer.AddButton(btn)
        btnsizer.Realize()
        sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
        self.SetSizer(sizer)
        sizer.Fit(self)

class panel_var_clase_p(panel_var_clase):
    '''Panel de constantes de clase'''
    def __init__(self, parent, panel_principal, idioma = None):
        '''Constructor de clase'''        
        panel_var_clase.__init__(self, parent)
        # Panel principal.
        self.panel_principal = panel_principal
        # Idioma.
        self.l = idioma
        # Creamos columnas.
        self.__conf_lista_cte(self.m_lista_cte, t(u"constante = 'valor'", self.l))
        # Binding.
        self.m_lista_cte.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)

    def salvar_cte_clase(self):
        '''Guardamos constantes de clase'''
        # Obtenemos clases.
        clases = self.panel_principal.panel_ogl.modelo.clases()
        # Nombre de la clase actual.
        nombre_clase = self.panel_principal.panel_def_clases.m_textCtrl_nc.GetValue()
        # Identificamos la clase a editar en el modelo.
        for i in clases: 
            if i[0].nombre == nombre_clase:
                # Recogemos datos de constantes (variables).
                lista_cte = list()
                n_cte = self.m_lista_cte.GetItemCount()
                for j in range(n_cte):
                    k = self.m_lista_cte.GetItem(j).GetText()
                    lista_cte.append(k)
                # Guardamos datos en estructura interna.
                i[0].constantes = lista_cte
                break
            
    def limpiar_widget(self):
        '''Limpiar widgets'''
        self.m_lista_cte.DeleteAllItems()
        
    def __conf_lista_cte(self, lista, texto):
        '''Configuración de panel de constantes'''
        lista.InsertColumn(0, texto)
        lista.SetColumnWidth(0, 500)

    def OnContextMenu(self, event):
        '''Menú contextual, al hacer click botón derecho sobre el panel'''
        # Crear elemento.
        self.id_crear = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnCrearCte, id=self.id_crear)
        # Modificar elemento.
        self.id_modificar = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnModificarCte, id=self.id_modificar)
        # Eliminar elemento.
        self.id_eliminar = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnEliminarCte, id=self.id_eliminar)
        # Subir un elemento en lo más alto.
        self.id_subir = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnSubirCte, id=self.id_subir)
        # Bajar un elemento en lo más bajo.
        self.id_bajar = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnBajarCte, id=self.id_bajar)
        # Creamos un menú.
        menu = wx.Menu()
        # Elementos del menú.
        item_crear = wx.MenuItem(menu, self.id_crear,t(u"Crear", self.l))
        item_modificar = wx.MenuItem(menu, self.id_modificar,t(u"Modificar", self.l))
        item_eliminar = wx.MenuItem(menu, self.id_eliminar,t(u"Eliminar", self.l))
        item_subir = wx.MenuItem(menu, self.id_subir,t(u"Subir", self.l))
        item_bajar = wx.MenuItem(menu, self.id_bajar,t(u"Bajar", self.l))
        # Añadimos elementos al menú.
        menu.AppendItem(item_crear)
        menu.AppendItem(item_modificar)
        menu.AppendItem(item_eliminar)
        menu.AppendSeparator()
        menu.AppendItem(item_subir)
        menu.AppendItem(item_bajar)
        # Mostramos el PopMenu.
        self.PopupMenu(menu)
        # Cuando se quita el PopMenu se tiene que limpiar memoria.
        menu.Destroy()

    def __datos_constantes(self, a, opcion = 0, elem_a_modif = None):
        '''Inserción de datos de constantes en el panel'''
        # Clave/Valor.
        t1 = a.text_clave.GetValue().strip()
        t2 = a.text_valor.GetValue().strip()
        if len(t1) == 0 or len(t2) == 0: return
        # Formamos cadena.
        cadena1 = '%s = %s' % (t1, t2)        
        # Lo incluimos en el control de lista.
        if opcion == 0:
            n = self.m_lista_cte.GetItemCount()
            self.m_lista_cte.InsertStringItem(n,cadena1)
        if opcion == 1:
            self.m_lista_cte.SetStringItem(elem_a_modif, 0, cadena1)

    def __mover_item(self):
        '''Desplazamiento de elementos en el panel'''
        aux = self.m_lista_cte
        if aux.GetSelectedItemCount() > 1:
            wx.MessageBox(t(u"Seleccione solo un elemento a desplazar", self.l), t(u"Atención", self.l),wx.OK)
            return None, None
        # Obtenemos el elemento seleccionado.
        item_sel = aux.GetFirstSelected()
        if item_sel == -1: 
            return None, None
        else: 
            # Guardamos el valor.
            cadena = aux.GetItemText(item_sel)
            # Eliminamos el valor.
            aux.DeleteItem(item_sel)
            # Devolvemos el contenido del elemento.
            return cadena, aux

    def OnSubirCte(self, event):
        '''Subir constante'''
        # Obtenemos el elemento seleccionado.
        cadena, aux = self.__mover_item()
        if cadena is None: return
        # Insertamos el elemento el primero.
        aux.InsertStringItem(0,cadena)

    def OnBajarCte(self, event):
        '''Bajar constante'''
        # Obtenemos el elemento seleccionado.
        cadena, aux = self.__mover_item()
        if cadena is None: return
        # Insertamos el elemento el último.
        n = aux.GetItemCount()    
        aux.InsertStringItem(n,cadena)

    def OnCrearCte(self, event):
        '''Crear constante'''
        a = dialogo_cte_clase(self, self.l)
        a.Show()
        if a.ShowModal() == wx.ID_OK: 
            self.__datos_constantes(a)
        # Limpiamos memoria y nos vamos.
        a.Destroy()

    def OnModificarCte(self, event):
        '''Modificar constante'''
        aux = self.m_lista_cte
        # Creamos el diálogo.            
        a = dialogo_cte_clase(self, self.l)
        if aux.GetSelectedItemCount() > 1:
            wx.MessageBox(t(u"Seleccione solo un elemento a modificar", self.l), t(u"Atención", self.l), wx.OK)
            a.Destroy()
            return
        # Obtenemos el elemento seleccionado. Si no hay nada seleccionado, nos vamos.
        item_sel = aux.GetFirstSelected()
        if item_sel == -1: 
            a.Destroy()
            return
        # Mostramos el diálogo.
        a.Show()
        if a.ShowModal() == wx.ID_OK: 
            self.__datos_constantes(a, 1, item_sel)
        # Limpiamos memoria y nos vamos.
        a.Destroy()

    def OnEliminarCte(self, event):
        '''Eliminar constante'''
        aux = self.m_lista_cte
        while True:
            x = aux.GetFirstSelected()
            aux.DeleteItem(x)
            if x == -1: break
